/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.ybuildingmemberrl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.client.utils.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.facedoor.modular.memberuser.entity.MemberUser;
import vip.xiaonuo.facedoor.modular.memberuser.service.MemberUserService;
import vip.xiaonuo.facedoor.modular.memberuser.vo.MemberImportResultPojoVO;
import vip.xiaonuo.facedoor.modular.memberuser.vo.UserImportResultVO;
import vip.xiaonuo.modular.remoteapi.stairs.RemoteStairsConstant;
import vip.xiaonuo.modular.remoteapi.stairs.RemoteStairsConstant.DeviceSyncStatus;
import vip.xiaonuo.modular.sync.DeviceEvent;
import vip.xiaonuo.modular.ybuildingmemberrl.entity.IdNameBar;
import vip.xiaonuo.modular.ybuildingmemberrl.entity.YBuildingMemberRl;
import vip.xiaonuo.modular.ybuildingmemberrl.enums.YBuildingMemberRlExceptionEnum;
import vip.xiaonuo.modular.ybuildingmemberrl.mapper.YBuildingMemberRlMapper;
import vip.xiaonuo.modular.ybuildingmemberrl.param.YBuildingMemberRlParam;
import vip.xiaonuo.modular.ybuildingmemberrl.service.YBuildingMemberRlService;
import vip.xiaonuo.modular.ydeviceevent.entity.YDeviceEvent;
import vip.xiaonuo.modular.ydeviceevent.mapper.YDeviceEventMapper;
import vip.xiaonuo.modular.yelevatordevice.entity.YElevatorDevice;
import vip.xiaonuo.modular.yelevatordevice.mapper.YElevatorDeviceMapper;
import vip.xiaonuo.modular.yelevatordevice.service.YElevatorDeviceService;
import vip.xiaonuo.sys.modular.file.enums.FileTypeEnum;
import vip.xiaonuo.sys.modular.file.service.SysFileInfoService;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 建筑人员关联service接口实现类
 *
 * @author 胡鹏达
 * @date 2022-08-29 10:49:46
 */
@Service
@Slf4j
public class YBuildingMemberRlServiceImpl extends ServiceImpl<YBuildingMemberRlMapper, YBuildingMemberRl> implements YBuildingMemberRlService {

  @Resource
  private YBuildingMemberRlMapper mapper;

  @Resource
  private YDeviceEventMapper deviceEventMapper;

  @Resource
  private YElevatorDeviceService elevatorDeviceService;

  @Resource
  private YElevatorDeviceMapper elevatorDeviceMapper;

  @Resource
  private SysFileInfoService sysFileInfoService;

  @Resource
  private MemberUserService memberUserService;


  @Override
  public void export(YBuildingMemberRlParam YBuildingMemberRlParam) {
    List<YBuildingMemberRl> list = mapper.findList(YBuildingMemberRlParam);
    PoiUtil.exportExcelWithStream("梯控人员.xls", YBuildingMemberRl.class, list);
  }


  @Override
  public PageResult<YBuildingMemberRl> page(YBuildingMemberRlParam yBuildingMemberRlParam) {
    return new PageResult<>(mapper.findPage(PageFactory.defaultPage(), yBuildingMemberRlParam));
  }


  @Override
  public List<YBuildingMemberRl> list(YBuildingMemberRlParam yBuildingMemberRlParam) {
    return this.list();
  }

  @Override
  public void add(YBuildingMemberRlParam memberRl) {

    List<YBuildingMemberRl> buildingMemberRls = this.findList(new YBuildingMemberRlParam().setBuildingId(memberRl.getBuildingId()).setMemberId(memberRl.getMemberId()));
    if (CollectionUtils.isNotEmpty(buildingMemberRls)) {
      throw new ServiceException(500, "已经存在该楼栋下设备的关联关系！");
    }
    // 查找楼栋下的所有设备
    List<YElevatorDevice> devices = elevatorDeviceMapper.selectList(new LambdaQueryWrapper<YElevatorDevice>().eq(YElevatorDevice::getBuildingId, memberRl.getBuildingId()));
    if (CollectionUtils.isEmpty(devices)) {
      throw new ServiceException(500, "该楼栋下不存在设备！");
    }

    if (StringUtils.isNotBlank(memberRl.getHandFloor()) && memberRl.getHandFloor().contains("，")) {
      throw new ServiceException(500, "请输入英文逗号！");
    }

    if (StringUtils.isNotBlank(memberRl.getHandFloor()) && memberRl.getHandFloor().split(",").length > 20) {
      throw new ServiceException(500, "最多20个手选楼层！");
    }


    for (YElevatorDevice device : devices) {
      YBuildingMemberRl yBuildingMemberRl = new YBuildingMemberRl();
      BeanUtil.copyProperties(memberRl, yBuildingMemberRl);
      yBuildingMemberRl.setDeviceId(device.getId());
      // 设置为新增人员中
      yBuildingMemberRl.setDeviceSyncStatus(RemoteStairsConstant.DeviceSyncStatus.ADD);
      this.save(yBuildingMemberRl);

      // 保存事件
      YDeviceEvent deviceEvent = new YDeviceEvent();
      deviceEvent.setDeviceNo(device.getDeviceNo());
      deviceEvent.setStatus(DeviceEvent.NEW);
      deviceEvent.setSysType(1);
      deviceEvent.setCreateDate(new Date());
      deviceEvent.setBody(yBuildingMemberRl.getId().toString());
      deviceEvent.setType(RemoteStairsConstant.RequestCmd.ADD_PERSON);
      deviceEventMapper.insert(deviceEvent);
    }
  }

  @Override
  public void batchUpdate(YBuildingMemberRlParam param) {
    List<YBuildingMemberRl> memberRls = this.list(new LambdaQueryWrapper<YBuildingMemberRl>()
            .eq(YBuildingMemberRl::getMemberId, param.getMemberId()).eq(YBuildingMemberRl::getBuildingId,param.getBuildingId()));
    for (YBuildingMemberRl memberRl : memberRls) {
      if (!Objects.equals(memberRl.getDeviceSyncStatus(), RemoteStairsConstant.DeviceSyncStatus.SYNC_SUCCESS)) {
        throw new ServiceException(500, "设备未同步完毕! 请稍后再试！！");
      }
    }

    for (YBuildingMemberRl memberRl : memberRls) {
      memberRl.setDeviceRole(param.getDeviceRole());
      memberRl.setHandFloor(param.getHandFloor());
      memberRl.setHandFloor(param.getHandFloor());
      memberRl.setDeviceSyncStatus(DeviceSyncStatus.UPDATE);
      this.updateById(memberRl);
      // 人员修改事件
      YElevatorDevice device = elevatorDeviceService.getById(memberRl.getDeviceId());
      YDeviceEvent deviceEvent = new YDeviceEvent();
      deviceEvent.setDeviceNo(device.getDeviceNo());
      deviceEvent.setStatus(DeviceEvent.NEW);
      deviceEvent.setSysType(1);
      deviceEvent.setBody(memberRl.getId().toString());
      deviceEvent.setType(RemoteStairsConstant.RequestCmd.UPDATE_PERSON);
      deviceEventMapper.insert(deviceEvent);
    }

  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void delete(YBuildingMemberRlParam entity) {
    YBuildingMemberRl yBuildingMemberRl = mapper.selectById(entity.getId());
    if (ObjectUtil.equal(entity.getDelFlag(), Boolean.TRUE)) {
      this.removeById(entity.getId());
      return;
    }

    if (!Objects.equals(yBuildingMemberRl.getDeviceSyncStatus(), RemoteStairsConstant.DeviceSyncStatus.SYNC_SUCCESS)) {
      throw new ServiceException(500, "设备未同步完毕! 请稍后再试！！");
    }
    yBuildingMemberRl.setDeviceSyncStatus(RemoteStairsConstant.DeviceSyncStatus.DELETE);
    this.updateById(yBuildingMemberRl);

    // 存在任务表
    YElevatorDevice device = elevatorDeviceService.getById(yBuildingMemberRl.getDeviceId());
    YDeviceEvent deviceEvent = new YDeviceEvent();
    deviceEvent.setDeviceNo(device.getDeviceNo());
    deviceEvent.setType(RemoteStairsConstant.RequestCmd.DELETE_PERSON);
    deviceEvent.setCreateDate(new Date());
    deviceEvent.setBody(entity.getMemberId() + ":" + entity.getMemberId());
    deviceEvent.setStatus(DeviceEvent.NEW);
    deviceEvent.setSysType(1);
    deviceEventMapper.insert(deviceEvent);
  }

  @Transactional(rollbackFor = Exception.class)
  @Override
  public void edit(YBuildingMemberRlParam entity) {
    YBuildingMemberRl yBuildingMemberRl = this.queryYBuildingMemberRl(entity);
    if (!Objects.equals(yBuildingMemberRl.getDeviceSyncStatus(), RemoteStairsConstant.DeviceSyncStatus.SYNC_SUCCESS)
            && !Objects.equals(yBuildingMemberRl.getDeviceSyncStatus(), RemoteStairsConstant.DeviceSyncStatus.SYNC_ERROR)) {
      throw new ServiceException(500, "设备未同步完毕! 请稍后再试！");
    }
    if (StringUtils.isNotBlank(entity.getHandFloor()) && entity.getHandFloor().contains("，")) {
      throw new ServiceException(500, "请输入英文逗号！");
    }

    if (StringUtils.isNotBlank(entity.getHandFloor()) && entity.getHandFloor().split(",").length > 20) {
      throw new ServiceException(500, "最多20个手选楼层！");
    }

    YDeviceEvent errorEventEntity = deviceEventMapper.selectByBody(yBuildingMemberRl.getId().toString());

    if (errorEventEntity != null) {
      if (errorEventEntity.getType().equals(RemoteStairsConstant.RequestCmd.UPDATE_PERSON)) {
        // 人员修改事件
        YElevatorDevice device = elevatorDeviceService.getById(yBuildingMemberRl.getDeviceId());
        YDeviceEvent deviceEvent = new YDeviceEvent();
        deviceEvent.setDeviceNo(device.getDeviceNo());
        deviceEvent.setStatus(DeviceEvent.NEW);
        deviceEvent.setSysType(1);
        deviceEvent.setBody(yBuildingMemberRl.getId().toString());
        deviceEvent.setType(RemoteStairsConstant.RequestCmd.UPDATE_PERSON);
        deviceEventMapper.insert(deviceEvent);

      } else {
        // 保存事件
        YElevatorDevice device = elevatorDeviceService.getById(yBuildingMemberRl.getDeviceId());
        YDeviceEvent deviceEvent = new YDeviceEvent();
        deviceEvent.setDeviceNo(device.getDeviceNo());
        deviceEvent.setStatus(DeviceEvent.NEW);
        deviceEvent.setCreateDate(new Date());
        deviceEvent.setSysType(1);
        deviceEvent.setBody(yBuildingMemberRl.getId().toString());
        deviceEvent.setType(RemoteStairsConstant.RequestCmd.ADD_PERSON);
        deviceEventMapper.insert(deviceEvent);
      }
    } else {
      // 人员修改事件
      YElevatorDevice device = elevatorDeviceService.getById(yBuildingMemberRl.getDeviceId());
      YDeviceEvent deviceEvent = new YDeviceEvent();
      deviceEvent.setDeviceNo(device.getDeviceNo());
      deviceEvent.setStatus(DeviceEvent.NEW);
      deviceEvent.setCreateDate(new Date());
      deviceEvent.setSysType(1);
      deviceEvent.setBody(yBuildingMemberRl.getId().toString());
      deviceEvent.setType(RemoteStairsConstant.RequestCmd.UPDATE_PERSON);
      deviceEventMapper.insert(deviceEvent);
    }

    yBuildingMemberRl.setHandFloor(entity.getHandFloor());
    yBuildingMemberRl.setLiveFloor(entity.getLiveFloor());
    yBuildingMemberRl.setDeviceSyncStatus(RemoteStairsConstant.DeviceSyncStatus.UPDATE);
    this.updateById(yBuildingMemberRl);
  }

  @Override
  public YBuildingMemberRl detail(YBuildingMemberRlParam yBuildingMemberRlParam) {
    return this.queryYBuildingMemberRl(yBuildingMemberRlParam);
  }

  @Override
  public List<YBuildingMemberRl> selectAllByDeviceId(Long deviceId, String status) {
    return mapper.selectAllByDeviceId(deviceId, status);
  }

  @Override
  public void deleteByDeviceId(Long deviceId) {
    mapper.deleteByDeviceId(deviceId);
  }

  @Override
  public void deleteByMemberId(Long memberId) {
    mapper.deleteByMemberId(memberId);
  }

  @Override
  public void updateByMemberIdAndDeviceId(Long memberId, Long deviceId, String status) {
    mapper.updateByMemberIdAndDeviceId(memberId, deviceId, status);
  }

  @Override
  public void deleteByMemberIdAndDeviceId(Long deviceId, Long memberId) {
    mapper.deleteByMemberIdAndDeviceId(deviceId, memberId);
  }

  @Override
  public YBuildingMemberRl selectByMemberIdAndDeviceId(Long deviceId, Long memberId) {
    return mapper.selectByMemberIdAndDeviceId(deviceId, memberId);
  }

  @Override
  public List<YBuildingMemberRl> selectAllByMemberId(Long memberId) {
    return mapper.selectAllByMemberId(memberId);
  }

  @Override
  public List<IdNameBar> selectAllDeviceName(Long memberId) {
    return mapper.selectAllDeviceName(memberId);
  }

  @Override
  public Integer selectMemberDeiviceId(Long visitorId, Long deviceId) {
    return mapper.selectMemberDeiviceId(visitorId, deviceId);
  }

  @Override
  public List<YBuildingMemberRl> findList(YBuildingMemberRlParam yBuildingMemberRl) {
    return mapper.findList(yBuildingMemberRl);
  }

  @Override
  public UserImportResultVO importExcel(MultipartFile file) {
    List<YBuildingMemberRl> visitorImportVOS = PoiUtil.importExcel(file, 0, 1, YBuildingMemberRl.class);
    CopyOnWriteArrayList<MemberImportResultPojoVO> memberImportResultPojoVos = new CopyOnWriteArrayList<>();
    // 保存文件
    sysFileInfoService.uploadFile(file, FileTypeEnum.LOCAL);

    AtomicInteger successNum = new AtomicInteger(0);
    AtomicInteger failureNum = new AtomicInteger(0);

    if (CollectionUtils.isEmpty(visitorImportVOS)) {
      throw new ServiceException(500, "文件中不存在有效数据!");
    }
    long d = System.currentTimeMillis();
    log.info("====导入开始时间==================================================" + DateUtils.formatDate(new Date()));
    if (visitorImportVOS.size() > 20) {
      log.info("开始多线程导入===");
      List<List<YBuildingMemberRl>> splitList = ListUtils.partition(visitorImportVOS, visitorImportVOS.size() / 20);
      CountDownLatch countDownLatch = new CountDownLatch(splitList.size());
      ExecutorService executorService = Executors.newFixedThreadPool(splitList.size());
      for (List<YBuildingMemberRl> oneList : splitList) {
        executorService.execute(() -> {
          try {
            signalThreadImport(memberImportResultPojoVos, successNum, failureNum, oneList);
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            countDownLatch.countDown();
          }
        });
      }
      try {
        countDownLatch.await();
      } catch (InterruptedException e) {
        log.error("线程被其他线程中断【{}】", ExceptionUtil.getMessage(e));
      }
    } else {
      log.info("开始单线程导入===");
      signalThreadImport(memberImportResultPojoVos, successNum, failureNum, visitorImportVOS);
    }
    // 有效数据

    log.info("====导入结束时间==================================================" + (System.currentTimeMillis() - d));
    UserImportResultVO memberImportResultVo = new UserImportResultVO();
    memberImportResultVo.setSuccessNum(successNum.get());
    memberImportResultVo.setFailNum(failureNum.get());
    memberImportResultVo.setMemberImportResultPojoVos(memberImportResultPojoVos);
    return memberImportResultVo;
  }

  private void addFailMessage(List<MemberImportResultPojoVO> memberImportResultPojoVos, YBuildingMemberRl buildingMemberRl, String failMessage, AtomicInteger failureNum) {
    MemberImportResultPojoVO memberImportResultPojoVo = new MemberImportResultPojoVO();
    memberImportResultPojoVo.setName(buildingMemberRl.getJobNum()).setFailMessage(failMessage);
    memberImportResultPojoVos.add(memberImportResultPojoVo);
    failureNum.incrementAndGet();
  }

  private void signalThreadImport(List<MemberImportResultPojoVO> memberImportResultPojoVos, AtomicInteger successNum, AtomicInteger failureNum, List<YBuildingMemberRl> yBuildingMemberRls) {
    for (YBuildingMemberRl importBean : yBuildingMemberRls) {
      try {
        List<MemberUser> memberUsers = memberUserService.list(new LambdaQueryWrapper<MemberUser>().eq(MemberUser::getJobNum, importBean.getJobNum()));

        YElevatorDevice device = elevatorDeviceService.getOne(new LambdaQueryWrapper<YElevatorDevice>().eq(YElevatorDevice::getDeviceNo, importBean.getDeviceNo()));

        if (CollectionUtils.isEmpty(memberUsers)) {
          addFailMessage(memberImportResultPojoVos, importBean, "人员不能为空", failureNum);
          continue;
        }

        if (StringUtils.isNotBlank(importBean.getHandFloor()) && importBean.getHandFloor().contains("，")) {
          addFailMessage(memberImportResultPojoVos, importBean, "  手选楼层不可使用中文逗号！", failureNum);
          continue;
        }

        MemberUser member = memberUsers.get(0);
        if (StringUtils.isBlank(member.getIcCard())) {
          addFailMessage(memberImportResultPojoVos, importBean, "  人员未绑定卡号！", failureNum);
          continue;
        }

        if (device == null) {
          addFailMessage(memberImportResultPojoVos, importBean, importBean.getDeviceNo() + "  未找到设备！", failureNum);
          continue;
        }

        if (device.getBuildingId() == null) {
          addFailMessage(memberImportResultPojoVos, importBean, importBean.getDeviceNo() + "  设备未绑定楼栋！", failureNum);
          continue;
        }
        if (StringUtils.isNotBlank(importBean.getHandFloor())){
          String[] split = importBean.getHandFloor().split(",");
          if (split.length>20){
            addFailMessage(memberImportResultPojoVos, importBean, "  最对20个手选楼层！", failureNum);
            continue;
          }
        }


        YBuildingMemberRl checkDb = mapper.selectByMemberIdAndDeviceId(device.getId(), member.getId());
        if (checkDb != null) {
          addFailMessage(memberImportResultPojoVos, importBean, member.getName() + "---" + device.getName() + "  已经绑定！", failureNum);
          continue;
        }


        memberAddEvent(successNum, importBean, member, device);
      } catch (Exception e) {
        log.error("用户【{}】 发生错误 错误信息【{}】", importBean.getJobNum(), ExceptionUtils.getMessage(e));
        addFailMessage(memberImportResultPojoVos, importBean, "发生异常错误!" + ExceptionUtils.getMessage(e), failureNum);
      }
    }

  }


  private void memberAddEvent(AtomicInteger successNum, YBuildingMemberRl buildingMemberRl, MemberUser member, YElevatorDevice device) {
    YBuildingMemberRl saveBean = new YBuildingMemberRl();
    saveBean.setMemberId(member.getId());
    saveBean.setDeviceId(device.getId());
    saveBean.setBuildingId(device.getBuildingId());
    saveBean.setDeviceRole(buildingMemberRl.getDeviceRole());
    saveBean.setLiveFloor(buildingMemberRl.getLiveFloor());
    saveBean.setHandFloor(StringUtils.isNotBlank(buildingMemberRl.getHandFloor())?buildingMemberRl.getHandFloor().trim():null);
    saveBean.setDeviceSyncStatus(RemoteStairsConstant.DeviceSyncStatus.UN_SYNC);
    this.save(saveBean);
    device.setMemberSyncStatus("0");
    elevatorDeviceService.updateById(device);
    successNum.incrementAndGet();
  }


  /**
   * 获取建筑人员关联
   *
   * @author 胡鹏达
   * @date 2022-08-29 10:49:46
   */
  private YBuildingMemberRl queryYBuildingMemberRl(YBuildingMemberRlParam yBuildingMemberRlParam) {
    YBuildingMemberRl yBuildingMemberRl = this.getById(yBuildingMemberRlParam.getId());
    if (ObjectUtil.isNull(yBuildingMemberRl)) {
      throw new ServiceException(YBuildingMemberRlExceptionEnum.NOT_EXIST);
    }
    return yBuildingMemberRl;
  }
}
